/**
 * @brief 		自定义常用函数库
 * @version 	V1.0
 * @author 		张凤远
 * @date   		2023年6月23日16:26:30
 */

#include "sys.h"
#include "Pro_Driver.h"

/**
 * @brief 					无符号16位比例缩放函数
 *
 * @param IN 				信号值输入
 * @param IN_MIN 			输入最小值
 * @param IN_MAX 			输入最大值
 * @param OUT_MIN 			输出最小值
 * @param OUT_MAX			输出最大值
 * @return 					比例缩放后的值
 */
u16 SCALE_U16(u16 IN, u16 IN_MIN, u16 IN_MAX, u16 OUT_MIN, u16 OUT_MAX)
{
	u16 IN_1;
	IN_1 = IN;
	if (IN_1 < IN_MIN)
	{
		IN_1 = IN_MIN;
	}
	else
	{
		IN_1 = IN;
	}
	if (IN_1 > IN_MAX)
	{
		IN_1 = IN_MAX;
	}
	else
	{
		IN_1 = IN;
	}
	return ((double)(IN_1 - IN_MIN) / (IN_MAX - IN_MIN)) * (OUT_MAX - OUT_MIN) + OUT_MIN;
}
/**
 * @brief 					有符号16位比例缩放函数
 *
 * @param IN 				输入值
 * @param IN_MIN 			输入最小值
 * @param IN_MAX 			输入最大值
 * @param OUT_MIN 			输出最小值
 * @param OUT_MAX 			输出最大值
 * @return 					s16 比例缩放后的值
 */
s16 SCALE_S16(s16 IN, s16 IN_MIN, s16 IN_MAX, s16 OUT_MIN, s16 OUT_MAX)
{
	s16 IN_1;
	IN_1 = IN;
	if (IN_1 < IN_MIN)
	{
		IN_1 = IN_MIN;
	}
	else
	{
		IN_1 = IN;
	}
	if (IN_1 > IN_MAX)
	{
		IN_1 = IN_MAX;
	}
	else
	{
		IN_1 = IN;
	}
	return ((double)(IN_1 - IN_MIN) / (IN_MAX - IN_MIN)) * (OUT_MAX - OUT_MIN) + OUT_MIN;
}
/**
 * @brief  					限幅滤波函数
 * 		   					优点：能有效克服因偶然因素引起的脉冲干扰；
 * 		   					缺点：无法抑制那种周期性的干扰、平滑度差。
 * @param IN 				信号输入值
 * @param DEVIATION_MAX 	最大偏离值
 * @return 					u16 滤波后的信号值
 */
u16 AmplitudeLimiting_Filter(u16 IN, u16 DEVIATION_MAX)
{
	static u16 value;
	u16 new_value;
	new_value = IN;
	if ((new_value - value > DEVIATION_MAX) || (value - new_value > DEVIATION_MAX))
	{
		return value;
	}
	value = new_value;
	return new_value;
}
/**
 * @brief 					中位值滤波函数
 * 							优点：能有效克服因偶然因素引起的波动干扰；对温度、液位的变化缓慢的被测参数有良好的滤波效果；
 * 							缺点：对流量、速度等快速变化的参数不宜。
 * @param Smpl_Tm 			采样时间，必须是主循环时间10ms的整数倍；
 * @param Smpl_Nmbr 		采样值数量，当前版本输入值必须为 5；
 * @param IN 				信号输入值
 * @return 					s16 滤波后的信号值
 */
s16 Median_Filter(u16 Smpl_Tm, u8 Smpl_Nmbr, s16 IN)
{
	s16 value_buf[5];
	u8 count;
	u8 i;
	u8 j;
	s16 temp;

	for (count = 0; count < Smpl_Nmbr; count++)
	{
		value_buf[count] = IN;
		delay_ms(Smpl_Tm);
	}

	for (j = 0; j < Smpl_Nmbr - 1; j++)
	{
		for (i = 0; i < Smpl_Nmbr - j; i++)
		{
			if (value_buf[i] > value_buf[i + 1])
			{
				temp = value_buf[i];
				value_buf[i] = value_buf[i + 1];
				value_buf[i + 1] = temp;
			}
		}
	}

	return value_buf[(Smpl_Nmbr - 1) / 2];
}
/**
 * @brief 					算数平均滤波函数
 * 							优点：适用于对一般具有随机干扰的信号进行滤波。这样信号的特点是有一个平均值，信号在某一数值范围附近上下波动；
 * 							缺点：对于测量速度较慢或要求数据计算速度较快的实时控制不适用，比较浪费RAM。
 * @param Smpl_Tm 			采样时间，必须是主循环时间10ms的整数倍；
 * @param Smpl_Nmbr 		采样值数量，N值较大时：信号平滑度较高，但灵敏度较低;
 *									   N值较小时：信号平滑度较低，但灵敏度较高;
 *									   N值的选取(参考)：流量，N=12；压力，N=4；
 * @param IN 				信号输入值
 * @return 					滤波后的信号值
 */
s16 Average_Filter(u16 Smpl_Tm, u8 Smpl_Nmbr, s16 IN)
{
	s16 sum = 0;
	u8 count;
	for (count = 0; count < N; count++)
	{
		sum = sum + IN;
		delay_ms(Smpl_Tm);
	}

	return (s16)(sum / N);
}

u16 Time_Ramp(u16 Range, u16 Inc_Tm, u16 Dec_Tm, u16 IN)
{
	u16 target_val;					// 目标参考值
	static u16 present_ref;			// 当前参考值
	u16 Inc_step_val, Dec_step_val; // 当前参考值到目标参考值所需要的步数
	u16 Inc_inc_val, Dec_inc_val;	// 步长/斜率
	u16 Out_val;					// 返回的输出值
	target_val = IN;
	if (target_val - present_ref > 0)
	{
		Inc_step_val = (u16)((double)((target_val - present_ref) / Range)) * (Inc_Tm / 10);
		Inc_inc_val = (target_val - present_ref) / Inc_step_val;
		Out_val = present_ref;
		if (Inc_step_val > 1)
		{
			Out_val = Out_val + Inc_inc_val;
			Inc_step_val--;
		}
		else if (Inc_step_val == 1)
		{
			Out_val = target_val;
			Inc_step_val = 0;
		}
		else
		{
			/*
			不执行操作
			 */
		}
		present_ref = Out_val;
		return Out_val;
	}
	else if (target_val - present_ref < 0)
	{
		Dec_step_val = (u16)((double)((present_ref - target_val) / Range)) * (Dec_Tm / 10);
		Dec_inc_val = (present_ref - target_val) / Dec_step_val;
		Out_val = present_ref;
		if (Inc_step_val > 1)
		{
			Out_val = Out_val - Inc_inc_val;
			Inc_step_val--;
		}
		else if (Dec_inc_val == 1)
		{
			Out_val = target_val;
			Inc_step_val = 0;
		}
		else
		{
			/*
			不执行操作
			 */
		}
		present_ref = Out_val;
		return Out_val;
	}
	else
	{
		return target_val;
	}
}
